Skip to content

DEV: update examples on two JSON pages #1305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 17, 2025
Merged

DEV: update examples on two JSON pages #1305

merged 4 commits into from
Apr 17, 2025

Conversation

dwdougherty
Copy link
Collaborator

@dwdougherty dwdougherty commented Mar 20, 2025

DOC-5003

@LiorKogan:

I've updated the return values from each example on the two modified pages using the latest available Redis Stack Docker image. What I can't work out is how the values stack. For example, in the following sequence of commands,

127.0.0.1:6379> JSON.SET arr . '[""]'
OK
127.0.0.1:6379> JSON.DEBUG MEMORY arr
(integer) 64

the size, if I believe the current write-up, should be 8 + 8 = 16 bytes. But, inexplicably, it's 64 bytes. I don't know how that result is calculated. So, I'll need your help with the sizing explanations in the content/develop/data-types/json/ram.md document.

@dwdougherty dwdougherty added bug Something isn't working dev labels Mar 20, 2025
@dwdougherty dwdougherty requested a review from LiorKogan March 20, 2025 20:38
@dwdougherty dwdougherty self-assigned this Mar 20, 2025
Copy link
Contributor

@LiorKogan
Copy link
Member

@eranhd can you help here?

@ephraimfeldblum
Copy link

ephraimfeldblum commented Mar 23, 2025

@dwdougherty no, it could not be 8 + 8.

The size of an empty array is 8 because it consists only of a pointer to a static "null" array. if it is non-empty, we need to store the additional metadata info (size, capacity) which is 16 more bytes.

Why it's 64 and not 32, I'll investigate. (Although it might just be as simple as the array having extra unused capacity.)

@ephraimfeldblum
Copy link

Yes, the array is created with default capacity 4. I did not investigate why. That leaves us with 56 bytes of used memory.

The additional 8 bytes comes from, as far as I can tell, a mistaken double counting of the string. It is being counted once when accounting for the used capacity of the array, and being counted again when recursively counting the memory consumed by the values stored in the array.

@LiorKogan @eranhd this should probably be fixed.

@ephraimfeldblum
Copy link

The expected behavior should be

127.0.0.1:6379> json.set a . '["", ""]'
OK
127.0.0.1:6379> json.debug memory a
(integer) 56
127.0.0.1:6379> json.set a . '["", "", ""]'
OK
127.0.0.1:6379> json.debug memory a
(integer) 56
127.0.0.1:6379> json.set a . '["", "", "", ""]'
OK
127.0.0.1:6379> json.debug memory a
(integer) 56
127.0.0.1:6379> json.set a . '["", "", "", "", ""]'
OK
127.0.0.1:6379> json.debug memory a
(integer) 88

@dwdougherty
Copy link
Collaborator Author

dwdougherty commented Apr 16, 2025

Hi @ephraimfeldblum. Would you please break down the first example, '[""]' for me byte for byte? I want to make sure I have it right in the JSON memory page.

BTW, in my latest commit, I re-ran all the examples using the 8.0-rc1 bits.

@ephraimfeldblum
Copy link

ephraimfeldblum commented Apr 17, 2025

Absolutely,

All JSON values are 8 bytes because the type used to represent them is a thin wrapper around a pointer. The information about what kind each value is is stored in the lower bits of the pointer. They are guaranteed to be zero because of alignment restrictions, therefore we can use them to store some entropy.

For some kinds of JSON values, that's all there is to it. Nulls and bools require not even that. Small integer values are already stored in static memory because we expect them to be frequently used, so they also take no more memory than the initial 8 bytes. Similarly, empty strings, arrays, and objects do not require any bookkeeping, and they can point to a static "null" string, array, or object as appropriate. You can create a database with as many of any of those as you like, and each instance will consume only the initial 8 bytes with no added allocations beyond that.

Once an array value (in this example) is filled with subvalues, extra metadata is required to track the allocations being done. 8 bytes are used each to quantify the allocated capacity and the real size of the array, totaling 16 bytes. So an array with only one contained value consumes: 8 bytes of the initial array value pointer + 16 bytes of metadata + and 8 × capacity bytes of allocated memory. By default, the initial capacity is 4. In total, that comes out to 56 bytes. Since we don't reallocate memory until the initial capacity is filled, we can fill such an array with up to 4 values and the memory consumed does not change. Once the current capacity is insufficient to fit a new value, the array reallocates to double* its capacity. An array with 5 elements will have a capacity of 8, therefore consuming 8 + 16 + 8×8 = 88 bytes.

*Since this operation is potentially expensive, it is done geometrically, not linearly. That way its cost may be amortized over many insertions.

@LiorKogan
Copy link
Member

@ephraimfeldblum thank you!

@dwdougherty I believe we can add a paragraph along these lines, followed by @ephraimfeldblum 's text:

Redis' internal JSON encoding is optimized for both performance and memory footprint. Due to such optimizations, the reply of JSON.DEBUG MEMORY could be nonintuitive. For example...

@dwdougherty
Copy link
Collaborator Author

dwdougherty commented Apr 17, 2025

Thank you, @ephraimfeldblum! Much appreciated!

@dwdougherty dwdougherty requested a review from a team April 17, 2025 15:03
Copy link
Contributor

@andy-stark-redis andy-stark-redis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dwdougherty
Copy link
Collaborator Author

Thanks, @andy-stark-redis !

@dwdougherty dwdougherty merged commit 3a28c90 into main Apr 17, 2025
5 checks passed
@dwdougherty dwdougherty deleted the DOC-5003 branch April 17, 2025 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working dev
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants